package cc.magicjson.scenario.implement.module.jdbc.template.druid.filter;

import com.alibaba.druid.filter.logging.Log4j2Filter;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.proxy.jdbc.*;
import com.alibaba.druid.util.JdbcUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

@Component
public class CustomSQLLogFilter extends Log4j2Filter {

    private DruidDataSource druidDataSource;
    private static final String PROCESSED_FLAG = "custom_log_processed";

    @EventListener(ContextRefreshedEvent.class)
    public void onApplicationEvent(ContextRefreshedEvent event) {
        this.druidDataSource = event.getApplicationContext().getBean(DruidDataSource.class);
        if (!druidDataSource.getProxyFilters().contains(this)) {
            druidDataSource.getProxyFilters().add(this);
        }
    }

    @Override
    protected void statementExecuteAfter(StatementProxy statement, String sql, boolean firstResult) {
        logStatement(statement, sql, "executed", null, null, LogOperation.EXECUTE);
    }

    @Override
    protected void statementExecuteQueryAfter(StatementProxy statement, String sql, ResultSetProxy resultSet) {
        logStatement(statement, sql, "query executed", resultSet, null, LogOperation.QUERY);
    }

    @Override
    protected void statementExecuteUpdateAfter(StatementProxy statement, String sql, int updateCount) {
        logStatement(statement, sql, "update executed", null, updateCount, LogOperation.UPDATE);
    }

    private enum LogOperation {
        EXECUTE, QUERY, UPDATE
    }

    private void logStatement(StatementProxy statement, String sql, String operation, 
                            ResultSetProxy resultSet, Integer updateCount, LogOperation logOperation) {
        try {
            if (druidDataSource != null) {
                StringBuilder msg = buildBaseMessage(statement);
                
                // 添加ResultSet信息
                if (resultSet != null) {
                    msg.append(", rs-").append(resultSet.getId());
                }
                
                // 添加参数信息
                appendParameters(msg, statement);
                
                // 添加执行信息
                msg.append("} ").append(operation);
                
                // 添加更新计数
                if (updateCount != null) {
                    msg.append(". effort ").append(updateCount);
                }
                
                // 添加执行时间和SQL
                msg.append(". ")
                   .append(statement.getLastExecuteTimeNano() / 1000000.0)
                   .append(" millis. ")
                   .append(sql);

                statementLog(msg.toString());
            }
        } catch (Exception e) {
            // 根据操作类型调用对应的父类方法
            switch (logOperation) {
                case EXECUTE:
                    super.statementExecuteAfter(statement, sql, false);
                    break;
                case QUERY:
                    super.statementExecuteQueryAfter(statement, sql, resultSet);
                    break;
                case UPDATE:
                    super.statementExecuteUpdateAfter(statement, sql, updateCount);
                    break;
            }
        }
    }

    private StringBuilder buildBaseMessage(StatementProxy statement) {
        StringBuilder msg = new StringBuilder();
        msg.append("{conn-")
           .append(statement.getConnectionProxy().getId())
           .append(", ")
           .append(stmtId(statement))
           .append(", ")
           .append(PROCESSED_FLAG)
           .append(", active-conn-")
           .append(druidDataSource.getActiveCount())
           .append(", total-conn-")
           .append(druidDataSource.getConnectCount());
        return msg;
    }

    private void appendParameters(StringBuilder msg, StatementProxy statement) {
        if (statement instanceof PreparedStatementProxy) {
            PreparedStatementProxy pstmt = (PreparedStatementProxy) statement;
            msg.append(", params:[");
            
            int parametersSize = pstmt.getParametersSize();
            for (int i = 0; i < parametersSize; i++) {
                if (i > 0) {
                    msg.append(", ");
                }
                appendParameter(msg, pstmt.getParameter(i));
            }
            msg.append("]");
        }
    }

    private void appendParameter(StringBuilder msg, JdbcParameter param) {
        if (param != null) {
            msg.append(param.getValue())
               .append("(")
               .append(JdbcUtils.getTypeName(param.getSqlType()))
               .append(")");
        } else {
            msg.append("null");
        }
    }

    private String stmtId(StatementProxy statement) {
        if (statement instanceof CallableStatementProxy) {
            return "cstmt-" + statement.getId();
        } else if (statement instanceof PreparedStatementProxy) {
            return "pstmt-" + statement.getId();
        } else {
            return "stmt-" + statement.getId();
        }
    }

    // 禁用不需要的日志
    @Override
    public void setStatementCreateAfterLogEnabled(boolean enable) {
        super.setStatementCreateAfterLogEnabled(false);
    }

    @Override
    public void setStatementCloseAfterLogEnabled(boolean enable) {
        super.setStatementCloseAfterLogEnabled(false);
    }

    @Override
    public void setStatementParameterClearLogEnable(boolean enable) {
        super.setStatementParameterClearLogEnable(false);
    }

    @Override
    public void setStatementParameterSetLogEnabled(boolean enable) {
        super.setStatementParameterSetLogEnabled(false);
    }

    @Override
    protected void statementLog(String message) {
        // 跳过不需要的日志
        if (message.contains("clearParameters") || 
            message.contains("clearBatch") || 
            message.contains("created") || 
            message.contains("closed") ||
            message.contains("Parameters :") ||
            message.contains("Types :")) {
            return;
        }
        
        // 避免重复处理
        if (message.contains(PROCESSED_FLAG)) {
            super.statementLog(message);
            return;
        }

        // 处理执行相关的日志
        if (message.contains("executed")) {
            super.statementLog(message);
        }
    }
}
